package com.song.flowable.controller.process;

import com.alibaba.fastjson.JSONObject;
import com.song.flowable.common.ResponseFactory;
import com.song.flowable.common.cmd.DeployModelCmd;
import com.song.flowable.common.cmd.SaveModelEditorCmd;
import com.song.flowable.common.cmd.UnDeployModelCmd;
import com.song.flowable.result.ResultEntity;
import com.song.flowable.util.FileUtil;
import com.song.flowable.view.dto.ModelQueryParam;
import com.song.flowable.view.model.PageModel;
import com.song.flowable.view.po.ModelRequest;
import com.song.flowable.view.vo.ModelResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ModelQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.Min;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 流程分类 前端控制器
 * </p>
 *
 * @author song
 * @since 2025-01-09
 */
@Api(tags = "流程模型 控制器")
@RestController
@RequestMapping("//process-model")
public class ProcessModelController {

    @Autowired
    protected RepositoryService repositoryService;

    @Autowired
    protected ManagementService managementService;

    @Autowired
    protected ResponseFactory responseFactory;

    @ApiImplicitParams({
            @ApiImplicitParam(value = "当前页码", name = "pageNum", defaultValue = "1"),
            @ApiImplicitParam(value = "每页条数", name = "pageSize", defaultValue = "10")
    })
    @ApiOperation(value = "分页查询流程模型")
    @PostMapping("/pageList")
    public ResultEntity pageList(
            ModelQueryParam modelQueryParam,
            @Min(value = 1) int pageNum,
            @Min(value = 1) int pageSize
    ){
        ModelQuery modelQuery = repositoryService.createModelQuery();
        if (ObjectUtils.isNotEmpty(modelQueryParam.getName())){
            modelQuery.modelName(modelQueryParam.getName());
        }
        if (ObjectUtils.isNotEmpty(modelQueryParam.getCategory())){
            modelQuery.modelCategory(modelQueryParam.getCategory());
        }
        modelQuery.orderByCreateTime().desc();
        List<Model> models = modelQuery.listPage(pageNum - 1, pageSize);
        List<ModelResponse> responses = models.stream().map(m -> {
            ModelResponse modelResponse = responseFactory.createModelResponse(m);
            return modelResponse;
        }).collect(Collectors.toList());
        long total = modelQuery.count();
        PageModel pageModel = PageModel.of(pageNum, pageSize);
        pageModel.setTotal(total);
        pageModel.setPages(pageModel.countPages());
        pageModel.setRecords(responses);
        return ResultEntity.success(pageModel);
    }

    @ApiOperation(value = "新增流程模型")
    @PostMapping("/addModel")
    public ResultEntity addModel(@RequestBody ModelRequest modelRequest){
        boolean exists = checkModelCategoryExists(modelRequest.getCategory());
        if (!exists){
            Model model = repositoryService.newModel();
            model.setKey(modelRequest.getKey());
            model.setName(modelRequest.getName());
            model.setVersion(1);
            model.setMetaInfo(modelRequest.getMetaInfo());
            model.setTenantId(modelRequest.getTenantId());
            model.setCategory(modelRequest.getCategory());
            repositoryService.saveModel(model);
            return ResultEntity.success("模型创建成功");
        }
        return ResultEntity.failMessage("模型标识已存在");
    }

    @ApiOperation(value = "保存模型流程设计")
    @PostMapping("/saveModelEditor")
    public ResultEntity saveModelEditor(@RequestBody ModelRequest modelRequest){
        Model model = repositoryService.getModel(modelRequest.getId());
        String metaInfo = model.getMetaInfo();
        String warningRequestUrl = "";
        String endUrl = "";
        if(StringUtils.isNotEmpty(metaInfo)) {
            warningRequestUrl = JSONObject.parseObject(metaInfo).getString("warningRequestUrl");
            endUrl = JSONObject.parseObject(metaInfo).getString("endUrl");
        }
        String editor = FileUtil.readXmlToString("D:\\song\\gitee\\spring-flowable\\src\\main\\resources\\processes\\ask_for_leave.bpmn20.xml");
        managementService.executeCommand(new SaveModelEditorCmd(modelRequest.getId(), editor, warningRequestUrl, endUrl));
        return ResultEntity.success();
    }

    @ApiOperation(value = "部署模型")
    @PostMapping("/deploy")
    public ResultEntity deploy(@RequestParam String id){
        managementService.executeCommand(new DeployModelCmd(id));
        return ResultEntity.success();
    }

    @ApiOperation(value = "停止部署模型")
    @PostMapping("/undeploy")
    public ResultEntity undeploy(@RequestParam String id){
        managementService.executeCommand(new UnDeployModelCmd(id));
        return ResultEntity.success();
    }

    @ApiOperation(value = "删除模型")
    @PostMapping("/delete")
    public ResultEntity delete(@RequestParam String id){
        repositoryService.deleteModel(id);
        return ResultEntity.success();
    }

    @ApiOperation(value = "获取模型详情信息")
    @GetMapping("/detail")
    public ResultEntity detail(@RequestParam String id) throws UnsupportedEncodingException {
        Model model = getModelById(id);
        ModelResponse modelResponse = responseFactory.createModelResponse(model);
        if (model.hasEditorSource()) {
            byte[] editorBytes = repositoryService.getModelEditorSource(model.getId());
            String editor = new String(editorBytes, "UTF-8");
            modelResponse.setEditor(editor);
        }
        return ResultEntity.success(modelResponse);
    }

    /**
     * 检查模型标识是否存在
     * @param category
     * @return
     */
    protected boolean checkModelCategoryExists(String category) {
        long countNum = repositoryService.createModelQuery().modelCategory(category).count();
        return countNum > 0;
    }

    /**
     * 模型ID查模型详情
     * @param modelId
     * @return
     */
    protected Model getModelById(String modelId) {
        Model model = repositoryService.getModel(modelId);
        if (model == null) {
            throw new FlowableObjectNotFoundException("No model found with id " + modelId);
        }
        return model;
    }
}
